#pragma once
#include<iostream>
#include"ResourceUtil.h"
using namespace std;

//负责数据检索
class ColOperator{ //不存储数据，仅负责组织调用
private:

    //两个vec应有相同的size
    static vector<Basic*> getExistDataVec(const vector<Basic*>& targetDataVec, const vector<bool>& judgeResVec){
        vector<Basic*> existTargetDataVec;
        for(size_t i = 0; i < targetDataVec.size(); i++){
            if(judgeResVec[i]){
                existTargetDataVec.push_back(targetDataVec[i]);
            }
        }
        return existTargetDataVec;
    }

    static void bitmapJudge(BitMap* bitMap, vector<bool>& judgeRes, const vector<pair<Basic*, size_t>>& judgeDataVec, const bool& isSnapShot){
        for(const auto& it : judgeDataVec){
            const double& hashVal = it.first->getHashVal();
            judgeRes[it.second] = isSnapShot ? bitMap->snapShotContains(hashVal) : bitMap->contains(hashVal);
        }
    }

    static void indexSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, const vector<pair<Basic*, size_t>>& searchDataVec, const bool& isSnapShot){
        for(const auto& it : searchDataVec){
            Basic* data = it.first;
            //locInfoVec里的指针都是索引里未经拷贝的原数据
            const vector<LocInfo*>& locInfoVec = isSnapShot ? index->snapShotGet(data) : index->get(data);
            LocInfoUtil::insertMergeSortLocInfo(totalMergeLocInfo, locInfoVec);
        }
    }


    static void indexRangeSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, Basic* targetData, const bool& isSnapShot, const bool& isLeftRange, const bool& isIncludeTarget){
        if(isLeftRange){
            if(isIncludeTarget){
                LocInfoUtil::insertMergeSortLocInfo(totalMergeLocInfo, isSnapShot ? index->snapShotGetFloor(targetData) : index->getFloor(targetData));
            }
            else {
                LocInfoUtil::insertMergeSortLocInfo(totalMergeLocInfo, isSnapShot ? index->snapShotGetLower(targetData) : index->getLower(targetData));
            }
        }
        else {
            if(isIncludeTarget){
                LocInfoUtil::insertMergeSortLocInfo(totalMergeLocInfo, isSnapShot ? index->snapShotGetCeiling(targetData) : index->getCeiling(targetData));
            }
            else{
                LocInfoUtil::insertMergeSortLocInfo(totalMergeLocInfo, isSnapShot ? index->snapShotGetHigher(targetData) : index->getHigher(targetData));
            }
        }
    }


    static void blockErgodic(Block* block, set<int>& indSet, const vector<Basic*>& sortTargetDataVec, const bool& isSnapShot){
        const size_t& snapShotSize = block->getSnapShotSize();
        for(size_t ind = 0; ind < snapShotSize; ind++){
            Basic* basicData = isSnapShot ? block->getSnapShotData(ind) : block->getData(ind);
            if(CheckIsInUtil::isInSortVec(sortTargetDataVec, basicData)){
                indSet.insert(ind);
            }
        }
    }

    static void blockRangeErgodic(Block* block, set<int>& indSet, Basic* targetData, const bool& isSnapShot, const bool& isLeftRange, const bool& isIncludeTarget){
        const size_t& snapShotSize = block->getSnapShotSize();
        for(size_t ind = 0; ind < snapShotSize; ind++){
            Basic* basicData = isSnapShot ? block->getSnapShotData(ind) : block->getData(ind);
            const bool& isFit = (isLeftRange ? basicCmp(basicData, targetData) : basicCmp(targetData, basicData)) ||
                                (isIncludeTarget ? basicEqu(basicData, targetData) : false);
            if(isFit){
                indSet.insert(ind);
            }
        }
    }

    static void snapShotBitMapJudge(BitMap* bitMap, vector<bool>& judgeRes, const vector<pair<Basic*, size_t>>& judgeDataVec){
        bitMap->getSnapShotLock(READ);
        bitmapJudge(bitMap, judgeRes, judgeDataVec, true);
        bitMap->releaseSnapShotLock();
    }

    static void currentBitMapJudge(BitMap* bitMap, vector<bool>& judgeRes, const vector<pair<Basic*, size_t>>& judgeDataVec, const LOCKTYPE& lockType, Transaction* transaction){
        bool isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(bitMap, lockType) : bitMap->getResLock(lockType);
        bitmapJudge(bitMap, judgeRes, judgeDataVec, false);
        if(!isInTransaction){
            bitMap->releaseResLock();
        }
    }


    static void snapShotIndexSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, const vector<pair<Basic*, size_t>>& searchDataVec){
        index->getSnapShotLock(READ);
        indexSearch(index, totalMergeLocInfo, searchDataVec, true);
        index->releaseSnapShotLock();
    }


    static void currentIndexSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, const vector<pair<Basic*, size_t>>& searchDataVec, const LOCKTYPE& lockType, Transaction* transaction){
        bool isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(index, lockType) : index->getResLock(lockType);
        indexSearch(index, totalMergeLocInfo, searchDataVec, false);
        if(!isInTransaction){
            index->releaseResLock();
        }
    }


    static void snapShotIndexRangeSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, Basic* targetData, const bool& isLeftRange, const bool& isIncludeTarget){
        index->getSnapShotLock(READ);
        indexRangeSearch(index, totalMergeLocInfo, targetData, true, isLeftRange, isIncludeTarget);
        index->releaseSnapShotLock();
    }


    static void currentIndexRangeSearch(SkipListIndex* index, map<int16_t, set<int>>& totalMergeLocInfo, Basic* targetData, const bool& isLeftRange, const bool& isIncludeTarget, const LOCKTYPE& lockType, Transaction* transaction){
        bool isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(index, lockType) : index->getResLock(lockType);
        indexRangeSearch(index, totalMergeLocInfo, targetData, false, isLeftRange, isIncludeTarget);
        if(!isInTransaction){
            index->releaseResLock();
        }
    }


    static void snapShotBlockErgodic(Block* block, set<int>& indSet, const vector<Basic*>& sortTargetDataVec){
        block->getSnapShotLock(READ);
        blockErgodic(block, indSet, sortTargetDataVec, true);
        block->releaseSnapShotLock();
    }


    static void currentBlockErgodic(Block* block, set<int>& indSet, const vector<Basic*>& sortTargetDataVec, const LOCKTYPE& lockType, Transaction* transaction){
        bool isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(block, lockType) : block->getResLock(lockType);
        blockErgodic(block, indSet, sortTargetDataVec, false);
        if(!isInTransaction){
            block->releaseResLock();
        }
    }


    static void snapShotBlockRangeErgodic(Block* block, set<int>& indSet, Basic* targetData, const bool& isLeftRange, const bool& isIncludeTarget){
        block->getSnapShotLock(READ);
        blockRangeErgodic(block, indSet, targetData, true, isLeftRange, isIncludeTarget);
        block->releaseSnapShotLock();
    }


    static void currentBlockRangeErgodic(Block* block, set<int>& indSet, Basic* targetData, const bool& isLeftRange, const bool& isIncludeTarget, const LOCKTYPE& lockType, Transaction* transaction){
        bool isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(block, lockType) : block->getResLock(lockType);
        blockRangeErgodic(block, indSet, targetData, false, isLeftRange, isIncludeTarget);
        if(!isInTransaction){
            block->releaseResLock();
        }
    }



    static vector<bool> snapShotOrCurrentBitMapJudge(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const bool& isSnapShot, const LOCKTYPE& lockType, Transaction* transaction){
        //依据ResourceInfo聚集 相同资源内的数据一并检查 减少对资源池请求
        const map<ResourceInfo, vector<pair<Basic*, size_t>>>& mergeJudgeInfo = ResourceUtil::getMergeIndexOrBitMapInfoAccrodData(tableInfo, colName, targetDataVec, false);
        vector<bool> judgeRes(targetDataVec.size(), false);
        for(const auto& it : mergeJudgeInfo){
            BitMap* bitMap = (BitMap*)ResourceUtil::getRes(it.first, transaction);
            string exceptionInfo = "";
            try {
                isSnapShot ? snapShotBitMapJudge(bitMap, judgeRes, it.second) :
                             currentBitMapJudge(bitMap, judgeRes, it.second, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ bitMap->releaseHoldLock(); }
            if(exceptionInfo != ""){ throw exceptionInfo; }
        }
        return judgeRes;
    }


    static map<int16_t, set<int>> snapShotOrCurrentIndexSearch(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const bool& isSnapShot, const LOCKTYPE& lockType, Transaction* transaction){
        //依据ResourceInfo聚集 相同资源内的数据一并检查 减少对资源池请求
        const map<ResourceInfo, vector<pair<Basic*, size_t>>>& mergeSearchInfo = ResourceUtil::getMergeIndexOrBitMapInfoAccrodData(tableInfo, colName, targetDataVec, true);
        map<int16_t, set<int>> searchRes;
        for(auto& it : mergeSearchInfo){
            SkipListIndex* index = (SkipListIndex*)ResourceUtil::getRes(it.first, transaction);
            string exceptionInfo = "";
            try {
                isSnapShot ? snapShotIndexSearch(index, searchRes, it.second) :
                             currentIndexSearch(index, searchRes, it.second, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ index->releaseHoldLock(); }
            if(exceptionInfo != ""){ throw exceptionInfo; }
        }
        return searchRes;
    }

    static map<int16_t, set<int>> snapShotOrCurrentDataErgodic(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const bool& isSnapShot, const LOCKTYPE& lockType, Transaction* transaction){
        const vector<Basic*>& sortDataVec = CheckIsInUtil::getSortDataVec(targetDataVec);
        const vector<ResourceInfo> colBlockResInfo = tableInfo->getColBlockResInfo(colName);
        map<int16_t, set<int>> ergodicRes;
        for(const ResourceInfo& resInfo : colBlockResInfo){
            Block* block = (Block*)ResourceUtil::getRes(resInfo, transaction);
            const int16_t& blockNo = resInfo.getBlockNo();
            string exceptionInfo = "";
            try {
                isSnapShot ? snapShotBlockErgodic(block, ergodicRes[blockNo], sortDataVec) :
                             currentBlockErgodic(block, ergodicRes[blockNo], sortDataVec, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ block->releaseHoldLock(); }
            if(exceptionInfo != ""){ throw exceptionInfo; }
        }
        return ergodicRes;
    }

    static map<int16_t, set<int>> snapShotOrCurrentRangeIndexSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const bool& isSnapShot, const bool& isLeftRange, const bool& isIncludeTarget, const LOCKTYPE& lockType, Transaction* transaction){
        const vector<ResourceInfo>& indexInfoVec = tableInfo->getRangeProbIndResInfo(colName, targetData->getHashVal(), isLeftRange);
        map<int16_t, set<int>> rangeSearchRes;
        for(const ResourceInfo& resInfo : indexInfoVec){
            SkipListIndex* index = (SkipListIndex*)ResourceUtil::getRes(resInfo, transaction);
            string exceptionInfo = "";
            try {
                isSnapShot ? snapShotIndexRangeSearch(index, rangeSearchRes, targetData, isLeftRange, isIncludeTarget) :
                             currentIndexRangeSearch(index, rangeSearchRes, targetData, isLeftRange, isIncludeTarget, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ index->releaseHoldLock(); }
            if(exceptionInfo != ""){ throw exceptionInfo; }
        }
        return rangeSearchRes;
    }


    static map<int16_t, set<int>> snapShotOrCurrentRangeDataErgodic(const TableInfo* tableInfo, const string& colName, Basic* targetData, const bool& isSnapShot, const bool& isLeftRange, const bool& isIncludeTarget, const LOCKTYPE& lockType, Transaction* transaction){
        const vector<ResourceInfo> colBlockResInfo = tableInfo->getColBlockResInfo(colName);
        map<int16_t, set<int>> ergodicRes;
        for(const ResourceInfo& resInfo : colBlockResInfo){
            Block* block = (Block*)ResourceUtil::getRes(resInfo, transaction);
            const int16_t& blockNo = resInfo.getBlockNo();
            string exceptionInfo = "";
            try {
                isSnapShot ? snapShotBlockRangeErgodic(block, ergodicRes[blockNo], targetData, isLeftRange, isIncludeTarget) :
                             currentBlockRangeErgodic(block, ergodicRes[blockNo], targetData, isLeftRange, isIncludeTarget, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ block->releaseHoldLock(); }
            if(exceptionInfo != ""){ throw exceptionInfo; }
        }
        return ergodicRes;
    }


    static map<int16_t, set<int>> snapShotOrCurrentDataSearch(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const bool& isSnapShot, const LOCKTYPE& lockType, Transaction* transaction){
        const vector<bool>& judgeResVec = isSnapShot ? snapShotBitMapJudge(tableInfo, colName, targetDataVec):
                                                       currentBitMapJudge(tableInfo, colName, targetDataVec, lockType, transaction);
        const vector<Basic*>& existTargetDataVec = getExistDataVec(targetDataVec, judgeResVec);
        if(existTargetDataVec.empty()){ return map<int16_t, set<int>>(); }
        if(tableInfo->getColInfo(colName)->getIsWithIndex()){
            return snapShotOrCurrentIndexSearch(tableInfo, colName, existTargetDataVec, isSnapShot, lockType, transaction);
        }
        return snapShotOrCurrentDataErgodic(tableInfo, colName, existTargetDataVec, isSnapShot, lockType, transaction);
    }


    static map<int16_t, set<int>> snapShotOrCurrentRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const bool& isSnapShot, const bool& isLeftRange, const bool& isIncludeTarget, const LOCKTYPE& lockType, Transaction* transaction){
        if(tableInfo->getColInfo(colName)->getIsWithIndex()){
            return snapShotOrCurrentRangeIndexSearch(tableInfo, colName, targetData, isSnapShot, isLeftRange, isIncludeTarget, lockType, transaction);
        }
        return snapShotOrCurrentRangeDataErgodic(tableInfo, colName, targetData, isSnapShot, isLeftRange, isIncludeTarget, lockType, transaction);
    }



public:

    static vector<bool> currentBitMapJudge(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentBitMapJudge(tableInfo, colName, targetDataVec, false, lockType, transaction);
    }

    static vector<bool> snapShotBitMapJudge(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec){
        return snapShotOrCurrentBitMapJudge(tableInfo, colName, targetDataVec, true, READ, nullptr);
    }

    static map<int16_t, set<int>> currentDataSearch(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentDataSearch(tableInfo, colName, targetDataVec, false, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotDataSearch(const TableInfo* tableInfo, const string& colName, const vector<Basic*>& targetDataVec){
        return snapShotOrCurrentDataSearch(tableInfo, colName, targetDataVec, true, READ, nullptr);
    }

    static map<int16_t, set<int>> currentHigherRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, false, false, false, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotHigherRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, true, false, false, READ, nullptr);
    }

    static map<int16_t, set<int>> currentLowerRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, false, true, false, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotLowerRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, true, true, false, READ, nullptr);
    }

    static map<int16_t, set<int>> currentCeilingRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, false, false, true, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotCeilingRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, true, false, true, READ, nullptr);
    }

    static map<int16_t, set<int>> currentFloorRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, false, true, true, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotFloorRangeDataSearch(const TableInfo* tableInfo, const string& colName, Basic* targetData){
        return snapShotOrCurrentRangeDataSearch(tableInfo, colName, targetData, true, true, true, READ, nullptr);
    }


};
